<template>
    <div style="position: relative">
        <div
            v-if="type === '2'"
            class="verify-img-out"
            :style="{ height: (parseInt(setSize.imgHeight) + vSpace) + 'px' }"
        >
            <div
                class="verify-img-panel"
                :style="{
                    width: setSize.imgWidth,
                    height: setSize.imgHeight,
                }"
            >
                <img
                    :src="'data:image/png;base64,' + backImgBase"
                    style="width: 100%; height: 100%; display: block;"
                />
                <div class="verify-refresh" @click="refresh" v-show="showRefresh">
                    <i class="iconfont icon-refresh"></i>
                </div>
                <transition name="tips">
                    <span
                        class="verify-tips"
                        v-if="tipWords"
                        :class="passFlag ? 'suc-bg' : 'err-bg'"
                    >{{ tipWords }}</span>
                </transition>
            </div>
        </div>
        <!-- 公共部分 -->
        <div
            class="verify-bar-area"
            :style="{
                width: setSize.imgWidth,
                height: barSize.height,
                'line-height': barSize.height
            }"
            ref="barArea"
        >
            <span class="verify-msg" v-text="text"></span>
            <div
                class="verify-left-bar"
                :style="{ width: (leftBarWidth !== undefined) ? leftBarWidth : barSize.height, height: barSize.height, 'border-color': leftBarBorderColor, transition: transitionWidth }"
            >
                <span class="verify-msg" v-text="finishText"></span>
                <div
                    class="verify-move-block"
                    @touchstart="start"
                    @mousedown="start"
                    :style="{ width: barSize.height, height: barSize.height, 'background-color': moveBlockBackgroundColor, left: moveBlockLeft, transition: transitionLeft }"
                >
                    <i :class="['verify-icon iconfont', iconClass]" :style="{ color: iconColor }"></i>
                    <div
                        v-if="type === '2'"
                        class="verify-sub-block"
                        :style="{
                            'width': Math.floor(parseInt(setSize.imgWidth) * 47 / 310) + 'px',
                            'height': setSize.imgHeight,
                            'top': '-' + (parseInt(setSize.imgHeight) + vSpace) + 'px',
                            'background-size': setSize.imgWidth + ' ' + setSize.imgHeight,
                        }"
                    >
                        <img
                            :src="'data:image/png;base64,' + blockBackImgBase"
                            style="width: 100%; height: 100%; display: block;"
                        />
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>
<script lang="ts">
export default {
    name: 'VerifySlide'
}
</script>

<script setup lang="ts">
import CryptoJS from 'crypto-js'
import { getCaptcha, checkCaptcha } from "@/api/auth/captcha"
import { onMounted, reactive, ref, watch, nextTick, toRefs, getCurrentInstance, ComponentPublicInstance } from 'vue'

const props = withDefaults(defineProps<{
    captchaType: string,
    type: string,
    mode: 'fixed' | 'pop',
    vSpace: number,
    explain: string,
    imgSize: { width: string, height: string },
    blockSize: { width: string, height: string },
    barSize: { width: string, height: string }
}>(), {
    type: '1',
    mode: 'fixed',
    vSpace: 5,
    explain: '向右滑动拼合拼图',
    imgSize: () => {
        return {
            width: '310px',
            height: '155px'
        }
    },
    blockSize: () => {
        return {
            width: '50px',
            height: '50px'
        }
    },
    barSize: () => {
        return {
            width: '310px',
            height: '40px'
        }
    }
})
const emits = defineEmits<{
    (event: 'close'): void
    (event: 'closeClickShow'): void
}>()

const { mode, captchaType, vSpace, type, explain } = toRefs(props)
const { imgSize, blockSize, barSize } = props
const proxy = getCurrentInstance()?.proxy as ComponentPublicInstance
let secretKey = ref<string>(''),           //后端返回的ase加密秘钥
    passFlag = ref<boolean>(),         //是否通过的标识
    backImgBase = ref<string>(''),      //验证码背景图片
    blockBackImgBase = ref<string>(''), //验证滑块的背景图片
    backToken = ref<string>(''),        //后端返回的唯一token值
    startMoveTime = ref<string>(''),    //移动开始的时间
    endMovetime = ref<string>(''),      //移动结束的时间
    tipsBackColor = ref<string>(''),    //提示词的背景颜色
    tipWords = ref<string>(''),
    text = ref<string>(''),
    finishText = ref<string>(''),
    setSize = reactive({
        imgHeight: '0',
        imgWidth: '0',
        barHeight: '0',
        barWidth: '0'
    }),
    top = ref(0),
    left = ref(0),
    moveBlockLeft = ref<string>(),
    leftBarWidth = ref<string>(),
    // 移动中样式
    moveBlockBackgroundColor = ref<string>(),
    leftBarBorderColor = ref('#ddd'),
    iconColor = ref<string>(),
    iconClass = ref('icon-right'),
    status = ref(false),	    //鼠标状态
    isEnd = ref(false),		//是够验证完成
    showRefresh = ref(true),
    transitionLeft = ref<string>(),
    transitionWidth = ref<string>(),
    startLeft = ref(0)

const barArea = ref()
function init() {
    text.value = explain.value
    getPictrue()
    nextTick(() => {
        let { imgHeight, imgWidth, barHeight, barWidth } = resetSize(proxy)
        setSize.imgHeight = imgHeight
        setSize.imgWidth = imgWidth
        setSize.barHeight = barHeight
        setSize.barWidth = barWidth
        proxy.$parent?.$emit('ready', proxy)
    })

    window.removeEventListener("touchmove", function (e) {
        move(e)
    })
    window.removeEventListener("mousemove", function (e) {
        move(e)
    })

    //鼠标松开
    window.removeEventListener("touchend", function () {
        end()
    })
    window.removeEventListener("mouseup", function () {
        end()
    })

    window.addEventListener("touchmove", function (e) {
        move(e)
    })
    window.addEventListener("mousemove", function (e) {
        move(e)
    })

    //鼠标松开
    window.addEventListener("touchend", function () {
        end()
    })
    window.addEventListener("mouseup", function () {
        end()
    })
}
watch(type, () => {
    init()
})
onMounted(() => {
    // 禁止拖拽
    init()
    proxy.$el.onselectstart = function () {
        return false
    }
})
//鼠标按下
function start(e: any) {
    e = e || window.event
    if (!e.touches) {  //兼容PC端 
        var x = e.clientX
    } else {           //兼容移动端
        var x = e.touches[0].pageX
    }
    startLeft.value = Math.floor(x - barArea.value.getBoundingClientRect().left)
    startMoveTime.value = (+new Date()).toString()    //开始滑动的时间
    if (isEnd.value == false) {
        text.value = ''
        moveBlockBackgroundColor.value = '#337ab7'
        leftBarBorderColor.value = '#337AB7'
        iconColor.value = '#fff'
        e.stopPropagation()
        status.value = true
    }
}
//鼠标移动
function move(e: any) {
    e = e || window.event
    if (status.value && isEnd.value == false) {
        if (!e.touches) {  //兼容PC端 
            var x = e.clientX
        } else {           //兼容移动端
            var x = e.touches[0].pageX
        }
        var bar_area_left = barArea.value.getBoundingClientRect().left
        var move_block_left = x - bar_area_left //小方块相对于父元素的left值
        if (move_block_left >= barArea.value.offsetWidth - Math.floor(parseInt(blockSize.width) / 2) - 2) {
            move_block_left = barArea.value.offsetWidth - Math.floor(parseInt(blockSize.width) / 2) - 2
        }
        if (move_block_left <= 0) {
            move_block_left = Math.floor(parseInt(blockSize.width) / 2)
        }
        //拖动后小方块的left值
        moveBlockLeft.value = (move_block_left - startLeft.value) + "px"
        leftBarWidth.value = (move_block_left - startLeft.value) + "px"
    }
}

//鼠标松开
function end() {
    endMovetime.value = (+new Date()).toString()
    //判断是否重合
    if (status.value && isEnd.value == false) {
        var moveLeftDistance = parseInt((moveBlockLeft.value || '').replace('px', ''))
        moveLeftDistance = moveLeftDistance * 310 / parseInt(setSize.imgWidth)
        let data = {
            captchaType: captchaType.value,
            "pointJson": secretKey.value ? aesEncrypt(JSON.stringify({ x: moveLeftDistance, y: 5.0 }), secretKey.value) : JSON.stringify({ x: moveLeftDistance, y: 5.0 }),
            "token": backToken.value
        }
        checkCaptcha(data)
            .then((res: any) => {
                moveBlockBackgroundColor.value = '#5cb85c'
                leftBarBorderColor.value = '#5cb85c'
                iconColor.value = '#fff'
                iconClass.value = 'icon-check'
                showRefresh.value = false
                isEnd.value = true
                if (mode.value == 'pop') {
                    setTimeout(() => {
                        emits('closeClickShow')
                        refresh()
                    }, 1500)
                }
                passFlag.value = true
                tipWords.value = `${((parseInt(endMovetime.value) - parseInt(startMoveTime.value)) / 1000).toFixed(2)}s验证成功`
                var captchaVerification = secretKey.value ? aesEncrypt(backToken.value + '---' + JSON.stringify({ x: moveLeftDistance, y: 5.0 }), secretKey.value) : backToken.value + '---' + JSON.stringify({ x: moveLeftDistance, y: 5.0 })
                setTimeout(() => {
                    tipWords.value = ''
                    emits('close')
                    proxy.$parent?.$emit('success', { captchaVerification })
                }, 1000)
            })
            .catch(err => {
                moveBlockBackgroundColor.value = '#d9534f'
                leftBarBorderColor.value = '#d9534f'
                iconColor.value = '#fff'
                iconClass.value = 'icon-close'
                passFlag.value = false
                setTimeout(function () {
                    refresh()
                }, 1000)
                proxy.$parent?.$emit('error', proxy)
                tipWords.value = "验证失败"
                setTimeout(() => {
                    tipWords.value = ""
                }, 1000)
            })
        status.value = false
    }
}

const refresh = () => {
    showRefresh.value = true
    finishText.value = ''

    transitionLeft.value = 'left .3s'
    moveBlockLeft.value = '0'

    leftBarWidth.value = undefined
    transitionWidth.value = 'width .3s'

    leftBarBorderColor.value = '#ddd'
    moveBlockBackgroundColor.value = '#fff'
    iconColor.value = '#000'
    iconClass.value = 'icon-right'
    isEnd.value = false

    getPictrue()
    setTimeout(() => {
        transitionWidth.value = ''
        transitionLeft.value = ''
        text.value = explain.value
    }, 300)
}

// 请求背景图片和验证图片
function getPictrue() {
    let data = {
        captchaType: captchaType.value
    }
    getCaptcha(data).then((res: any) => {
        if (res.repCode == "0000") {
            backImgBase.value = res.repData.originalImageBase64
            blockBackImgBase.value = res.repData.jigsawImageBase64
            backToken.value = res.repData.token
            secretKey.value = res.repData.secretKey
        } else {
            tipWords.value = res.repMsg
        }
    })
}

/**
 * @word 要加密的内容
 * @keyWord `string`  服务器随机返回的关键字
 *  */
function aesEncrypt(word: string, keyWord = "XwKsGlMcdPMEhR1B") {
    var key = CryptoJS.enc.Utf8.parse(keyWord);
    var srcs = CryptoJS.enc.Utf8.parse(word);
    var encrypted = CryptoJS.AES.encrypt(srcs, key, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 });
    return encrypted.toString();
}

function resetSize(vm: any) {
    var img_width, img_height, bar_width, bar_height;	//图片的宽度、高度，移动条的宽度、高度

    var parentWidth = vm.$el.parentNode.offsetWidth
    var parentHeight = vm.$el.parentNode.offsetHeight
    if (vm.imgSize.width.indexOf('%') != -1) {
        img_width = parseInt(vm.imgSize.width) / 100 * parentWidth + 'px'
    } else {
        img_width = vm.imgSize.width;
    }

    if (vm.imgSize.height.indexOf('%') != -1) {
        img_height = parseInt(vm.imgSize.height) / 100 * parentHeight + 'px'
    } else {
        img_height = vm.imgSize.height
    }

    if (vm.barSize.width.indexOf('%') != -1) {
        bar_width = parseInt(vm.barSize.width) / 100 * parentWidth + 'px'
    } else {
        bar_width = vm.barSize.width
    }

    if (vm.barSize.height.indexOf('%') != -1) {
        bar_height = parseInt(vm.barSize.height) / 100 * parentHeight + 'px'
    } else {
        bar_height = vm.barSize.height
    }

    return { imgWidth: img_width, imgHeight: img_height, barWidth: bar_width, barHeight: bar_height }
}
</script>